#ifndef POISSON_CONSTRUCT_H_
#define POISSON_CONSTRUCT_H_
#include<Mesh_IO/Mesh_IO.h>
#include<algorithm/points_cloud_algorithm.h>

#ifdef __cplusplus
extern "C" {
#endif


typedef struct Poisson_OC_Prop{
    double normal[3],coeffs[3];

}Poisson_OC_Prop;

static inline double poisson_FF(double x)
{
    return (x<=0.5&&x>=-0.5)?(0.75-x*x):( (x<=1.5&&x>=-1.5)?(1.125-1.5*fabs(x)+x*x*0.5):( 0)  );
}
static inline double poisson_DFF(double x)
{
    return (x<=0.5&&x>=-0.5)?(-2*x):( (x<=1.5&&x>=-1.5)?(-1.5*SIGN(x)+x):( 0)  ); 
} 



static inline double oc_poisson_FF(double* x,OC_Node* ocnode)
{
    double temp_p[3]={(ocnode->loc_min[0]+ocnode->loc_max[0])/2.0,(ocnode->loc_min[1]+ocnode->loc_max[1])/2.0, (ocnode->loc_min[2]+ocnode->loc_max[2])/2.0};
    temp_p[0]=x[0]-temp_p[0];temp_p[1]=x[1]-temp_p[1];temp_p[2]=x[2]-temp_p[2];
    double w=ocnode->loc_max[0]-ocnode->loc_min[0];
    temp_p[0]/=w;   //temp_p[1]/=(ocnode->loc_max[1]-ocnode->loc_min[1]);temp_p[2]/=(ocnode->loc_max[2]-ocnode->loc_min[2]);
    temp_p[1]/=w;temp_p[2]/=w;
    //printf("%lf %lf %lf\n",w,ocnode->loc_max[1]-ocnode->loc_min[1],ocnode->loc_max[2]-ocnode->loc_min[2]);
    return poisson_FF(temp_p[0])*poisson_FF(temp_p[1])*poisson_FF(temp_p[2]);
    //return 9*poisson_FF(temp_p[0])*poisson_FF(temp_p[1])*poisson_FF(temp_p[2]);
}

static inline double oc_poisson_DFF(double *x,OC_Node*ocnode,int j)
{
    double temp_p[3]={(ocnode->loc_min[0]+ocnode->loc_max[0])/2.0,(ocnode->loc_min[1]+ocnode->loc_max[1])/2.0, (ocnode->loc_min[2]+ocnode->loc_max[2])/2.0};
    temp_p[0]=x[0]-temp_p[0];temp_p[1]=x[1]-temp_p[1];temp_p[2]=x[2]-temp_p[2];
    double w=ocnode->loc_max[0]-ocnode->loc_min[0];
    temp_p[0]/=w;   //temp_p[1]/=(ocnode->loc_max[1]-ocnode->loc_min[1]);temp_p[2]/=(ocnode->loc_max[2]-ocnode->loc_min[2]);
    temp_p[1]/=w;temp_p[2]/=w; 
    double re=1.0;
    for(int i=0;i<3;i++)
    {
        if(i==j)
        {
           re*=(poisson_DFF(temp_p[i])/w); 
        }
        else
        {
            re*=poisson_FF(temp_p[i]);
        }
    }  
    return re;
}
void poisson_oc_node_init_from_node(OC_Node*octree,Node* );
double poisson_oc_node_width(OC_Node* octree);


double* compute_value_according_basis_function(double*x,OC_Node*octree,int depth);
void points_cloud_compute_normal_using_clapack(Node* n,KD_Node*kdtree,int num);
void compute_octree_normal(OC_Node* octree,int depth);

Mesh* poisson_transfer_octree2vertices(OC_Node*octree,int depth);

double * compute_value_according_basis_function1(double*x,KD_Node* kdtree,double w);
double poisson_compute_b_i(template_v* v,KD_Node*kdtree,double w);


double poisson_compute_A_i_j(template_v* vi,template_v* vj ,double w);

Node*  compute_support_functions_nodes(double * x ,KD_Node*kdtree,double w );





#ifdef __cplusplus
}
#endif

#endif